import pandas as pd
import numpy as np
import random
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('TkAgg')
from getFuncton import get_train
import os
import math
# 读取数据
# data = pd.read_csv('ratings.csv', delimiter='\s+')
# train=data.sample(99900)
# test = data.drop(train.index)
# data=train

def funksvd(data,test,k=20):
    # 创建用户索引
    movie_idx = data['movieId'].unique()
    user_idx = data['userId'].unique()
    num_users = len(user_idx)



    # 创建稀疏矩阵
    row = data['userId'].map(lambda x: np.where(user_idx == x)[0][0])

    # col = data['movieId'] - 1
    col = data['movieId'].map(lambda x: np.where(movie_idx == x)[0][0])
    values = data['rating']

    # 创建随机初始矩阵
    # user_matrix = np.random.rand(num_users, 5)
    # item_matrix = np.random.rand(data['movieId'].nunique(), 5)
    user_matrix = np.random.rand(num_users, k)
    item_matrix = np.random.rand(data['movieId'].nunique(), k)

    # for i in range(data['userId'].nunique()):
    #     user_matrix[i] = [np.random.random() / math.sqrt(5) for x in range(k)]
    # for i in range(data['movieId'].nunique()):
    #     item_matrix[i] = [np.random.random() / math.sqrt(5) for x in range(k)]

    # 迭代训练
    learning_rate =0.0000001
    num_iterations = 100
    lambda_ = 0.01  # 设置 L2 正则化参数

    losslist=[]
    for i in range(num_iterations):
        # 计算预测评分和实际评分之差
        pred = np.dot(user_matrix, item_matrix.T)
        error = values.values - pred[row, col]

        # 更新参数并添加 L2 正则化
        user_matrix[row, :] += learning_rate * (np.sum(error[:, np.newaxis] * item_matrix[col, :], axis=0) - 2 * lambda_ * user_matrix[row, :])
        item_matrix += learning_rate * (np.sum(error[:, np.newaxis] * user_matrix[row, :], axis=0) - 2 * lambda_ * item_matrix)

        # 计算均方误差
        mse = np.mean(error**2)
        if i % 100 == 0:
            print("Iteration:", i, "MSE:", mse)
        losslist.append(mse)

    # 将用户矩阵与用户索引关联起来

    user_matrix = pd.DataFrame(user_matrix, index=user_idx)

    p=np.dot(user_matrix, item_matrix.T)
    # print(p)
    t=data.pivot_table(values='rating', index='userId', columns='movieId').fillna(0)
    t=t.to_numpy()
    # print(t)

    test_value=test["rating"]
    test_row = test['userId'].map(lambda x: np.where(user_idx == x)[0][0])
    test_col = test['movieId'].map(lambda x: np.where(movie_idx == x)[0][0])

    error = np.mean((test_value.values - pred[test_row, test_col])**2)
    error1=np.mean(abs(test_value.values - pred[test_row, test_col]))
    # print(error1)





    # return losslist
    return error1

# data=pd.read_csv("ratings.csv",sep="\s+")
# all = get_train(data)
# train = all[0]
# test = all[1]
# losslist=funksvd(train,test)
# x = list(range(len(losslist)))

# 使用 matplotlib 画折线图
# plt.plot(x, losslist)
#
# # 添加标题和轴标签
# plt.title('Line Chart with Single List')
# plt.xlabel('Index')
# plt.ylabel('Y Axis')
#
# # 显示网格线
# plt.grid(True)
#
# # 显示图形
# plt.show()


